package hexapawn.game;

import java.util.LinkedList;
import java.util.List;

/**
 * class Board - The object that contains two players and the entire board.
 * The main function of this class is to draw out the board and the pieces.
 * 
 * (0, 0) will be the top left corner and (row-1, column-1) will be the 
 * bottom right corner
 * 
 * This object contains a 2D array of Cell object: Cell board_space[row][column].
 * 
 * @author ChaoSXDemon
 *
 */
public class Board {

	private int row, column;
	private Cell[][] board_space;
	private Player p1, p2;
	private boolean turn;
	
	/**
	 * Default Constructor that creates a Board(3, 3) object
	 * 
	 */
	public Board(){
		this(3, 3);
	}
	
	/**
	 * Constructor - Creates a Board object with _row rows and _column columns
	 * 
	 * @param _row - The number of rows for the Board
	 * @param _column - The number of columns for the Board
	 */
	public Board(int _row, int _column){
		row = _row;
		column = _column;
		board_space = new Cell[row][column];
		for(int i=0; i<row; i++)
			for(int j=0; j<column; j++)
				board_space[i][j] = new Cell(i, j);
	}
	
	/**
	 * Setup Player 1 and Player 2 objects for this Board
	 * 
	 * @param _p1 - Player 1, the top player. This can also be the MDP AI.
	 * @param _p2 - Player 2, the bottom player. This can be the Mini-Max AI
	 * 				training against MDP AI.
	 */
	public void setupPlayers(Player _p1, Player _p2){
		p1 = _p1;
		p2 = _p2;
	}
	
	public void switchTurn(){
		turn = !turn;
	}
	
	public boolean isTopTurn(){
		return turn;
	}
	
	public boolean isBottomTurn(){
		return !turn;
	}
	
	/**
	 * Clears the Board and sets up new Cell object for the entire board.
	 * 
	 */
	public void clear(){
		for(int i=0; i<row; i++)
			for(int j=0; j<column; j++)
				board_space[i][j] = new Cell(i, j);
	}
	
	/**
	 * Get the cell above (row-1) the given cell variable. This method
	 * does not check for boundary.
	 * 
	 * @param cell - the start cell as reference.
	 * @return - the cell above cell variable
	 */
	public Cell getCellAbove(Cell cell){
		return board_space[cell.getRow()-1][cell.getColumn()];
	}
	
	/**
	 * Get the cell below (row+1) the given cell variable. This method
	 * does not check for boundary.
	 * 
	 * @param cell - the start cell as reference.
	 * @return - the cell below cell variable
	 */
	public Cell getCellBelow(Cell cell){
		return board_space[cell.getRow()+1][cell.getColumn()];
	}
	
	/**
	 * Get the cell above left (row-1, col-1) the given cell variable. This method
	 * does not check for boundary.
	 * 
	 * @param cell - the start cell as reference.
	 * @return - the cell above left cell variable
	 */
	public Cell getCellAboveLeft(Cell cell){
		return board_space[cell.getRow()-1][cell.getColumn()-1];
	}
	
	/**
	 * Get the cell above right (row-1, col+1) the given cell variable. This method
	 * does not check for boundary.
	 * 
	 * @param cell - the start cell as reference.
	 * @return - the cell above right cell variable
	 */
	public Cell getCellAboveRight(Cell cell){
		return board_space[cell.getRow()-1][cell.getColumn()+1];
	}
	
	/**
	 * Get the cell below left (row+1, col-1) the given cell variable. This method
	 * does not check for boundary.
	 * 
	 * @param cell - the start cell as reference.
	 * @return - the cell below left cell variable
	 */
	public Cell getCellBelowLeft(Cell cell){
		return board_space[cell.getRow()+1][cell.getColumn()-1];
	}
	
	/**
	 * Get the cell below right (row+1, col+1) the given cell variable. This method
	 * does not check for boundary.
	 * 
	 * @param cell - the start cell as reference.
	 * @return - the cell below right cell variable
	 */
	public Cell getCellBelowRight(Cell cell){
		return board_space[cell.getRow()+1][cell.getColumn()+1];
	}
	
	public int getWinner(){
		for(int j=0; j<column; j++){
			if(board_space[0][j].hasPiece()){
				if(board_space[0][j].getPiece().getOwner() == Player.PLAYER_2) return Player.PLAYER_2;
				if(board_space[0][j].getPiece().getOwner() == Player.PLAYER_MINIMAX) return Player.PLAYER_MINIMAX;
			}
			if(board_space[row-1][j].hasPiece()){
				if(board_space[row-1][j].getPiece().getOwner() == Player.PLAYER_1) return Player.PLAYER_1;
				if(board_space[row-1][j].getPiece().getOwner() == Player.PLAYER_MDP) return Player.PLAYER_MDP;
			}
		}
		return -1;	//No winner yet
	}
	
	public List<Cell> getTopPlayerCells(){
		List<Cell> list = new LinkedList<Cell>();
		for(int i=0; i<row; i++){
			for(int j=0; i<column; j++){
				Cell cell = board_space[i][j];
				if(cell.hasPiece()){
					if(cell.getPiece().getOwner() == Player.PLAYER_1 ||
					   cell.getPiece().getOwner() == Player.PLAYER_MDP){
						list.add(cell);
					}
				}
			}
		}
		return list;
	}
	
	public List<Cell> getBottomPlayerCells(){
		List<Cell> list = new LinkedList<Cell>();
		for(int i=0; i<row; i++){
			for(int j=0; i<column; j++){
				Cell cell = board_space[i][j];
				if(cell.hasPiece()){
					if(cell.getPiece().getOwner() == Player.PLAYER_2 ||
					   cell.getPiece().getOwner() == Player.PLAYER_MINIMAX){
						list.add(cell);
					}
				}
			}
		}
		return list;
	}
	
	/**
	 * Returns the top player. Player 1 is always the top player
	 * 
	 * @return - the top player
	 */
	public Player getTopPlayer(){
		return p1;
	}
	
	/**
	 * Returns the bottom player. Player 2 is always the bottom player
	 * 
	 * @return - the bottom player
	 */
	public Player getBottomPlayer(){
		return p2;
	}
	
	/**
	 * Returns the number of rows for this Board
	 * 
	 * @return - the number of rows
	 */
	public int getRow(){
		return row;
	}
	
	/**
	 * Returns the number of columns for this Board
	 * 
	 * @return - the number of columns
	 */
	public int getColumn(){
		return column;
	}
	
	/**
	 * Returns the 2D array of Cell objects representing
	 * this Board object.
	 * 
	 * @return - the 2D array of Cell objects
	 */
	public Cell[][] getCells(){
		return board_space;
	}
	
	public Board applyMove( Move m){
		Board newBoard = null;
		try {
			newBoard = (Board) this.clone();
			Cell from = m.getFrom();
			Cell to = m.getTo();
			newBoard.getCells()[from.getColumn()][from.getRow()].removePiece();
			newBoard.getCells()[to.getColumn()][to.getRow()].setPiece(to.getPiece());
		} catch (CloneNotSupportedException e) {
		}
		return newBoard;
	}
	
}
